package org.tamal.classinfo;

/**
 * This class represents different access flags of classes, methods or fields.
 * @author Tamal Kanti Nath
 */
public final class AccessFlag {

    /** Declared public; may be accessed from outside its package. */
    public static final int ACC_PUBLIC = 0x0001;
    /** Declared private; usable only within the defining class. */
    public static final int ACC_PRIVATE = 0x0002;
    /** Declared protected; may be accessed within subclasses. */
    public static final int ACC_PROTECTED = 0x0004;
    /** Declared static. */
    public static final int ACC_STATIC = 0x0008;
    /**
     * Declared final. <br/>
     * Class: No subclasses allowed.<br/>
     * Field: Never directly assigned to after object construction.<br/>
     * Method: Must not be overridden.
     */
    public static final int ACC_FINAL = 0x0010;
    /**
     * The super (class) or synchronized (method) flag.<br/>
     * Class: Treat superclass methods specially when invoked by the
     * invoke-special instruction.<br/>
     * Method: Declared synchronized; invocation is wrapped by a monitor use.
     */
    public static final int ACC_SYNCHRONIZED = 0x0020;
    /**
     * The volatile (field) or bridge (method) flag.<br/>
     * Field: Declared volatile; cannot be cached.<br/>
     * Method: A bridge method, generated by the compiler.
     */
    public static final int ACC_VOLATILE = 0x0040;
    /**
     * The transient (field) or varargs (method) flag.<br/>
     * Field: Declared transient; not written or read by a persistent object
     * manager.<br/>
     * Method: Declared with variable number of arguments.
     */
    public static final int ACC_TRANSIENT = 0x0080;
    /** Declared native; implemented in a language other than Java. */
    public static final int ACC_NATIVE = 0x0100;
    /** Is an interface, not a class. */
    public static final int ACC_INTERFACE = 0x0200;
    /**
     * Declared abstract.<br/>
     * Class: must not be instantiated.<br/>
     * Method: no implementation is provided.
     */
    public static final int ACC_ABSTRACT = 0x0400;
    /** Declared strictfp; floating-point mode is FP-strict. */
    public static final int ACC_STRICT = 0x0800;
    /** Declared synthetic; not present in the source code. */
    public static final int ACC_SYNTHETIC = 0x1000;
    /** Declared as an annotation type. */
    public static final int ACC_ANNOTATION = 0x2000;
    /** Declared as an enum type (class) or enum element (field). */
    public static final int ACC_ENUM = 0x4000;

    private static final String PRIVATE = "private ";
    private static final String PROTECTED = "protected ";
    private static final String PUBLIC = "public ";
    private static final String STATIC = "static ";
    private static final String FINAL = "final ";
    private static final String SUPER = "super ";
    private static final String INTERFACE = "interface ";
    private static final String ABSTRACT = "abstract ";
    private static final String SYNTHETIC = "synthetic ";
    private static final String ANNOTATION = "annotation ";
    private static final String ENUM = "enum ";
    private static final String VOLATILE = "volatile ";
    private static final String TRANSIENT = "transient ";
    private static final String SYNCHRONIZED = "synchronized ";
    private static final String BRIDGE = "bridge ";
    private static final String VARARGS = "barargs ";
    private static final String NATIVE = "native ";
    private static final String STRICT = "strict ";

    private AccessFlag() {
    }

    /**
     * Return true if the flag includes public modifier, false otherwise.
     * @param flag the flag
     * @return true if public; false otherwise
     */
    public static boolean isPublic(int flag) {
        return (flag & ACC_PUBLIC) == ACC_PUBLIC;
    }

    /**
     * Return true if the flag includes private modifier, false otherwise.
     * @param flag the flag
     * @return true if private; false otherwise
     */
    public static boolean isPrivate(int flag) {
        return (flag & ACC_PRIVATE) == ACC_PRIVATE;
    }

    /**
     * Return true if the flag includes protected modifier, false otherwise.
     * @param flag the flag
     * @return true if protected; false otherwise
     */
    public static boolean isProtected(int flag) {
        return (flag & ACC_PROTECTED) == ACC_PROTECTED;
    }

    /**
     * Return true if the flag includes static modifier, false otherwise.
     * @param flag the flag
     * @return true if static; false otherwise
     */
    public static boolean isStatic(int flag) {
        return (flag & ACC_STATIC) == ACC_STATIC;
    }

    /**
     * Return true if the flag includes final modifier, false otherwise.
     * @param flag the flag
     * @return true if final; false otherwise
     */
    public static boolean isFinal(int flag) {
        return (flag & ACC_FINAL) == ACC_FINAL;
    }

    /**
     * Return true if the flag includes super modifier, false otherwise.
     * The ACC_SUPER flag exists for backward compatibility.
     * @param flag the flag
     * @return true if super; false otherwise
     */
    public static boolean isSuper(int flag) {
        return (flag & ACC_SYNCHRONIZED) == ACC_SYNCHRONIZED;
    }

    /**
     * Return true if the flag includes synchronized modifier, false otherwise.
     * @param flag the flag
     * @return true if synchronized; false otherwise
     */
    public static boolean isSynchronized(int flag) {
        return (flag & ACC_SYNCHRONIZED) == ACC_SYNCHRONIZED;
    }

    /**
     * Return true if the flag includes volatile modifier, false otherwise.
     * @param flag the flag
     * @return true if volatile; false otherwise
     */
    public static boolean isVolatile(int flag) {
        return (flag & ACC_VOLATILE) == ACC_VOLATILE;
    }

    /**
     * Return true if the flag includes bridge modifier, false otherwise.
     * @param flag the flag
     * @return true if bridge; false otherwise
     */
    public static boolean isBridge(int flag) {
        return (flag & ACC_VOLATILE) == ACC_VOLATILE;
    }

    /**
     * Return true if the flag includes transient modifier, false otherwise.
     * @param flag the flag
     * @return true if transient; false otherwise
     */
    public static boolean isTransient(int flag) {
        return (flag & ACC_TRANSIENT) == ACC_TRANSIENT;
    }

    /**
     * Return true if the flag includes varargs modifier, false otherwise.
     * @param flag the flag
     * @return true if contains varargs; false otherwise
     */
    public static boolean isVarargs(int flag) {
        return (flag & ACC_TRANSIENT) == ACC_TRANSIENT;
    }

    /**
     * Return true if the flag includes native modifier, false otherwise.
     * @param flag the flag
     * @return true if native; false otherwise
     */
    public static boolean isNative(int flag) {
        return (flag & ACC_NATIVE) == ACC_NATIVE;
    }

    /**
     * Return true if the flag includes interface modifier, false otherwise.
     * @param flag the flag
     * @return true if interface; false otherwise
     */
    public static boolean isInterface(int flag) {
        return (flag & ACC_INTERFACE) == ACC_INTERFACE;
    }

    /**
     * Return true if the flag includes abstract modifier, false otherwise.
     * @param flag the flag
     * @return true if abstract; false otherwise
     */
    public static boolean isAbstract(int flag) {
        return (flag & ACC_ABSTRACT) == ACC_ABSTRACT;
    }

    /**
     * Return true if the flag includes strict modifier, false otherwise.
     * @param flag the flag
     * @return true if strict; false otherwise
     */
    public static boolean isStrict(int flag) {
        return (flag & ACC_STRICT) == ACC_STRICT;
    }

    /**
     * Return true if the flag includes synthetic modifier, false otherwise.
     * @param flag the flag
     * @return true if synthetic; false otherwise
     */
    public static boolean isSynthetic(int flag) {
        return (flag & ACC_SYNTHETIC) == ACC_SYNTHETIC;
    }

    /**
     * Return true if the flag includes annotation modifier, false otherwise.
     * @param flag the flag
     * @return true if annotation; false otherwise
     */
    public static boolean isAnnotation(int flag) {
        return (flag & ACC_ANNOTATION) == ACC_ANNOTATION;
    }

    /**
     * Return true if the flag includes enum modifier, false otherwise.
     * @param flag the flag
     * @return true if enum; false otherwise
     */
    public static boolean isEnum(int flag) {
        return (flag & ACC_ENUM) == ACC_ENUM;
    }

    /**
     * Returns string representation of a class flag.
     * @param flag the class flag
     * @return the string matching the flag
     */
    public static String getClassFlag(int flag) {
        StringBuilder buf = new StringBuilder();
        if (isPublic(flag)) {
            buf.append(PUBLIC);
        }
        if (isFinal(flag)) {
            buf.append(FINAL);
        }
        if (isSuper(flag)) {
            buf.append(SUPER);
        }
        if (isInterface(flag)) {
            buf.append(INTERFACE);
        }
        if (isAbstract(flag)) {
            buf.append(ABSTRACT);
        }
        if (isSynthetic(flag)) {
            buf.append(SYNTHETIC);
        }
        if (isAnnotation(flag)) {
            buf.append(ANNOTATION);
        }
        if (isEnum(flag)) {
            buf.append(ENUM);
        }
        return buf.toString();
    }

    /**
     * Returns string representation of a inner-class flag.
     * @param flag the inner-class flag
     * @return the string matching the flag
     */
    public static String getInnerClassFlag(int flag) {
        StringBuilder buf = new StringBuilder();
        if (isPublic(flag)) {
            buf.append(PUBLIC);
        }
        if (isPrivate(flag)) {
            buf.append(PRIVATE);
        }
        if (isProtected(flag)) {
            buf.append(PROTECTED);
        }
        if (isStatic(flag)) {
            buf.append(STATIC);
        }
        if (isFinal(flag)) {
            buf.append(FINAL);
        }
        if (isInterface(flag)) {
            buf.append(INTERFACE);
        }
        if (isAbstract(flag)) {
            buf.append(ABSTRACT);
        }
        if (isSynthetic(flag)) {
            buf.append(SYNTHETIC);
        }
        if (isAnnotation(flag)) {
            buf.append(ANNOTATION);
        }
        if (isEnum(flag)) {
            buf.append(ENUM);
        }
        return buf.toString();
    }

    /**
     * Returns string representation of a field flag.
     * @param flag the field flag
     * @return the string matching the flag
     */
    public static String getFieldFlag(int flag) {
        StringBuilder buf = new StringBuilder();
        if (isPublic(flag)) {
            buf.append(PUBLIC);
        }
        if (isPrivate(flag)) {
            buf.append(PRIVATE);
        }
        if (isProtected(flag)) {
            buf.append(PROTECTED);
        }
        if (isStatic(flag)) {
            buf.append(STATIC);
        }
        if (isFinal(flag)) {
            buf.append(FINAL);
        }
        if (isVolatile(flag)) {
            buf.append(VOLATILE);
        }
        if (isTransient(flag)) {
            buf.append(TRANSIENT);
        }
        if (isSynthetic(flag)) {
            buf.append(SYNTHETIC);
        }
        if (isEnum(flag)) {
            buf.append(ENUM);
        }
        return buf.toString();
    }

    /**
     * Returns string representation of a method flag.
     * @param flag the method flag
     * @return the string matching the flag
     */
    public static String getMethodFlag(int flag) {
        StringBuilder buf = new StringBuilder();
        if (isPublic(flag)) {
            buf.append(PUBLIC);
        }
        if (isPrivate(flag)) {
            buf.append(PRIVATE);
        }
        if (isProtected(flag)) {
            buf.append(PROTECTED);
        }
        if (isStatic(flag)) {
            buf.append(STATIC);
        }
        if (isFinal(flag)) {
            buf.append(FINAL);
        }
        if (isSynchronized(flag)) {
            buf.append(SYNCHRONIZED);
        }
        if (isBridge(flag)) {
            buf.append(BRIDGE);
        }
        if (isVarargs(flag)) {
            buf.append(VARARGS);
        }
        if (isNative(flag)) {
            buf.append(NATIVE);
        }
        if (isAbstract(flag)) {
            buf.append(ABSTRACT);
        }
        if (isStrict(flag)) {
            buf.append(STRICT);
        }
        if (isSynthetic(flag)) {
            buf.append(SYNTHETIC);
        }
        return buf.toString();
    }

}
